package com.dove.ohpm.service

import com.dove.ohpm.model.GlobalProfile
import com.dove.ohpm.model.PackageFile
import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileVisitor
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import org.json.JSONObject
import java.io.File
import java.nio.charset.StandardCharsets
import java.nio.file.Files
import java.nio.file.Paths
import kotlin.io.path.pathString

class ProjectLoader {
    companion object {
        var project: Project? = null
            private set
        val packages: MutableMap<String, VirtualFile> = mutableMapOf()
        private val dependencies: MutableMap<String, PackageFile> = mutableMapOf()

        fun getPackages(project: Project) {
            try {
                this.project = project
                val path = File(project.basePath, "build-profile.json5")
                val files = mutableListOf<String>()
                if (path.exists()) {
                    val json = Json { ignoreUnknownKeys = true }
                    val globalProfile =
                            json.decodeFromString<GlobalProfile>(String(path.readBytes(), StandardCharsets.UTF_8))
                    globalProfile.modules.forEach {
                        val file =
                                project.basePath?.let { it1 -> Paths.get(it1, it.srcPath, "oh-package.json5") }?.normalize()
                        if (file != null) {
                            val content = String(Files.readAllBytes(file), StandardCharsets.UTF_8)
                            val packageObject = json.decodeFromString<PackageFile>(content)
                            val key = packageObject.name
                            dependencies[key] = packageObject
                            files.add(file.pathString)
                        }
                        val op = File(project.basePath, "oh-package.json5")
                        if (op.exists()) {
                            val content = String(op.readBytes(), StandardCharsets.UTF_8)
                            val packageObject = json.decodeFromString<PackageFile>(content)
                            val key = packageObject.name
                            dependencies[key] = packageObject
                            files.add(op.absolutePath)
                        }
                    }
                    val contentRoots = ProjectRootManager.getInstance(project).contentRoots
                    contentRoots.forEach { root ->
                        VfsUtilCore.visitChildrenRecursively(root, object : VirtualFileVisitor<Void?>() {
                            override fun visitFile(file: VirtualFile): Boolean {
                                if (file.isValid && file.name.contains("oh-package.json5") && !file.path.contains("oh_modules")) {
                                    val content = String(file.contentsToByteArray(), StandardCharsets.UTF_8)
                                    val packageObject = json.decodeFromString<PackageFile>(content)
                                    val key = packageObject.name
                                    if (dependencies[key] != null && !packages.containsKey(key))
                                        packages[key] = file
                                }
                                return true
                            }
                        })
                    }
                }
            } catch (ex: Exception) {
                Messages.showErrorDialog(null as Project?, ex.message, "Error")
            }
        }

        fun getDependence(key: String): PackageFile {
            val depend = dependencies[key]
            if (depend == null) {
                throw Exception("文件未找到：$key")
            } else {
                return depend
            }
        }

        fun updateDependence(key: String, name: String, version: String) {
            try {
                val packageObject = dependencies[key]
                if (packageObject != null) {
                    val dependence = packageObject.dependencies?.entries?.firstOrNull { it.key == name }
                    if (dependence != null) {
                        dependence.setValue(version)
                    } else {
                        packageObject.dependencies?.set(name, version)
                    }
                }
            } catch (ex: Exception) {
                Messages.showErrorDialog(null as Project?, ex.message, "Error")
            }
        }

        fun removeDependence(key: String, name: String) {
            try {
                val packageObject = dependencies[key]
                if (packageObject != null) {
                    if (packageObject.dependencies?.containsKey(name) == true) {
                        packageObject.dependencies.remove(name)
                    }
                }
            } catch (ex: Exception) {
                Messages.showErrorDialog(null as Project?, ex.message, "Error")
            }
        }

        fun applyChange(key: String): String? {
            try {
                val packageFile = packages[key]
                val packageObject = dependencies[key]
                if (packageFile != null && packageObject != null) {
                    val content = Json.encodeToString(packageObject)
                    val json = JSONObject(content)
                    val prettyJsonString = json.toString(4)
                    runWriteAction {
                        packageFile.setBinaryContent(prettyJsonString.toByteArray(Charsets.UTF_8))
                    }
                    return packageFile.parent?.path
                }
            } catch (ex: Exception) {
                Messages.showErrorDialog(null as Project?, ex.message, "Error")
            }
            return null
        }
    }
}